/**
 * Software License, Version 1.0
 * 
 * Copyright 2008 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgment:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgment may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or Granules, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called Granules, 
 * nor may Indiana University or Community Grids Lab or Granules appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 * LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 * WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 * NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 * INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 * INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 * "VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 * LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 * ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 * GENERATED USING SOFTWARE.
 */
package cgl.granules.samples.matrix;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;
import java.util.Random;
import java.util.StringTokenizer;

import cgl.granules.dataset.DatasetCollection;
import cgl.granules.dataset.DatasetException;
import cgl.granules.dataset.DatasetFactory;
import cgl.granules.dataset.StreamingAccess;
import cgl.granules.exception.CommunicationsException;
import cgl.granules.exception.DeploymentException;
import cgl.granules.exception.MarshallingException;
import cgl.granules.operation.InstanceDeployer;
import cgl.granules.operation.MapReduceException;
import cgl.granules.results.ResultPayload;
import cgl.granules.results.Results;
import cgl.granules.results.ResultsFactory;
import cgl.granules.scheduler.StreamingService;
import cgl.granules.util.Matrix;
import cgl.granules.util.MatrixFactory;
import cgl.narada.event.NBEvent;
import cgl.narada.event.NBEventException;
import cgl.narada.event.TemplateProfileAndSynopsisTypes;
import cgl.narada.matching.Profile;
import cgl.narada.service.ServiceException;
import cgl.narada.service.client.EventConsumer;
import cgl.narada.service.client.EventProducer;
import cgl.narada.service.client.NBEventListener;

/**
 * An example demonstrating the calculation of matrix products on a set of
 * machines.
 * 
 * @author Shrideep Pallickara
 * 
 */
public class MatrixDeployer extends InstanceDeployer implements NBEventListener {

    private int completionCount = 0;
    private int startCount = 0;
    private int workUnits = 0;
    private int numberOfMachines = 0;

    private ResultPayload resultPayload = null;
    private Random random;
    private StreamingService streamingService;

    private EventProducer producer;
    private EventConsumer consumer;
    private String rowStream = "MatrixStreams/Row/";
    private String columnStream = "MatrixStreams/Column";

    private String workUnitStream = "FinishedWorkUnit/MatrixElement";
    private String computedColumnStream = "Computed/Column/";

    private String filenameA, filenameB;
    private Matrix matrixA, matrixB, matrixC;
    private boolean matricesInitialized = false;
    private String moduleName = "MatrixDeployer: ";


    /**
     * Initializes the deployer.
     * 
     * @param streamingProperties
     *            The properties for streaming
     * @param commType
     *            The communications type
     * @throws CommunicationsException
     *             If there are network problems during communications
     * @throws IOException
     *             If there are IO problems
     * @throws MarshallingException
     *             If there are marshalling erros
     * @throws DeploymentException
     *             If there are deployment related problems
     */
    public MatrixDeployer(Properties streamingProperties, String commType)
        throws ServiceException, CommunicationsException, IOException,
        MarshallingException, DeploymentException {

        initialize(streamingProperties, commType);

        random = new Random();
        resultPayload = ResultPayload.getInstance();

        streamingService = StreamingService.getInstance();
        while (!streamingService.isInitialized()) {
            try {
                System.out.println(moduleName
                    + "Streaming service NOT initialized!");
                Thread.sleep(20);
            } catch (InterruptedException e) {
                System.out.println(moduleName + "Problems trying to sleep!");
            }
        }

        producer = streamingService.createProducer();
        consumer = streamingService.createConsumer(this);

        consumeStream(workUnitStream, StreamingAccess.STRING_SYNOPSIS);
        consumeStream(computedColumnStream,
                      StreamingAccess.HIERARCHICAL_SYNOPSIS);
    }


    /**
     * Creates benchmark Matrices based on the specified arguments. The method
     * checks to see if the matrices need to be created by seeing if the files
     * already exist.
     * 
     * @param filenameA
     *            The file containing matrix-A
     * @param numOfRowsA
     *            The number of rows in matrix-A
     * @param numOfColumnsA
     *            The number of columns in matrix-A
     * @param filenameB
     *            The file containing matrix-B
     * @param numOfRowsB
     *            The number of rows in matrix-B
     * @param numOfColumnsB
     *            The number of columns in matrix-B
     * @throws IOException
     *             If there are IO problems during the read/write operations.
     */
    public void createBenchmarkMatrices(String filenameA, int numOfRowsA,
                                        int numOfColumnsA, String filenameB,
                                        int numOfRowsB, int numOfColumnsB)
        throws IOException {
        // String filenameA = "MatrixA.txt";

        int entriesType = Matrix.INT_ENTRIES;
        boolean rowMajorFormatA = true;

        MatrixFactory matrixFactory = MatrixFactory.getInstance();

        long start = System.nanoTime();
        matrixA =
            matrixFactory.getMatrix(filenameA, numOfRowsA, numOfColumnsA,
                                    entriesType, rowMajorFormatA);

        if (checkNeedToCreateMatrix(matrixA)) {
            for (int i = 0; i < numOfRowsA; i++) {
                int rowAi[] = matrixA.createDenseIntRow();
                matrixA.writeIntMatrixRow(i, rowAi);
            }
            System.out.println("Time to create/write matrixA [" + numOfRowsA
                + "," + numOfColumnsA + "] = "
                + ((System.nanoTime() - start) / 1000000) + " ms");
        }

        // String filenameB = "MatrixB.txt";
        boolean rowMajorFormatB = false;
        matrixB =
            matrixFactory.getMatrix(filenameB, numOfRowsB, numOfColumnsB,
                                    entriesType, rowMajorFormatB);

        if (checkNeedToCreateMatrix(matrixB)) {
            start = System.nanoTime();
            for (int i = 0; i < numOfRowsB; i++) {
                int[] columnBi = matrixB.createDenseIntColumn(numOfRowsB);
                matrixB.writeIntMatrixColumn(i, columnBi);
            }
            System.out.println("Time to write matrixB [" + numOfRowsB + ","
                + numOfColumnsB + "] = "
                + ((System.nanoTime() - start) / 1000000) + " ms");
        }

        createProductMatrix(numOfRowsA, numOfColumnsB);
        this.filenameA = filenameA;
        this.filenameB = filenameB;
        matricesInitialized = true;
    }


    /* Checks to see if the matrix needs to be created */
    private boolean checkNeedToCreateMatrix(Matrix matrix) throws IOException {
        long size = matrix.size();
        int metadataLength = matrix.getMetadataLength();
        int numOfRows = matrix.getNumberOfRows();
        int numOfColumns = matrix.getNumberOfColumns();

        long expectedSize = numOfRows * numOfColumns * 4 /* Matrix.INT_ENTRIES */
            + metadataLength;
        if (expectedSize != size) {
            System.out.println(moduleName + "Matrix File needs to be created"
                + " current size = " + size + ", expected size = "
                + expectedSize);
            return true;
        }

        return false;

    }


    /* Creates the product matrix */
    private void createProductMatrix(int numOfRowsA, int numOfColumnsB)
        throws IOException {
        String filenameC = "MatrixC.txt";
        int entriesType = Matrix.INT_ENTRIES;
        boolean rowMajorFormatC = false;

        MatrixFactory matrixFactory = MatrixFactory.getInstance();

        matrixC =
            matrixFactory.getMatrix(filenameC, numOfRowsA, numOfColumnsB,
                                    entriesType, rowMajorFormatC);
    }


    /**
     * Initializes a <code>MatrixMap</code> instance based on the specified
     * arguments.
     * 
     * @param row
     *            The row-id of matrix-A
     * @param column
     *            The column-id of matrix-B
     * @param numOfEntries
     *            The number of entries that need to be proceed.
     * @return The initialized <code>MatrixMap</code> instance
     * @throws DatasetException
     *             If there are problems initializing/using the datasets
     * @throws MapReduceException
     *             If there are problems related to Map/Reduce roles within the
     *             application.
     */
    public MatrixMap initializeMatrixMap(int row, int column, int numOfEntries)
        throws DatasetException, MapReduceException {
        MatrixMap map = new MatrixMap();

        Properties props = new Properties();
        String value = "" + column;
        String property = "matrix column";
        props.put(property, value);
        props.put("entries", numOfEntries + "");

        map.setProcessingDirectives(props);

        DatasetFactory datasetFactory = DatasetFactory.getInstance();
        StreamingAccess streamingAccess =
            datasetFactory.createStreamingDataset("DatasetID", "Testcase");

        String streamSynopsis1 = rowStream;
        String streamSynopsis2 = columnStream + column;

        streamingAccess.addInputStream(streamSynopsis1,
                                       StreamingAccess.HIERARCHICAL_SYNOPSIS);
        streamingAccess.addInputStream(streamSynopsis2,
                                       StreamingAccess.STRING_SYNOPSIS);

        DatasetCollection datasetCollection = map.getDatasetCollection();
        datasetCollection.addDataset(streamingAccess);

        map.setAsExecuteWhenDataAvailable();
        return map;
    }


    /**
     * Generates workloads for the various <code>MatrixMap</code> instances that
     * have been deployed on the available resources.
     * 
     * @param numOfRows
     *            The number of rows in the matrix
     * @param numOfColumns
     *            The number of columns in the matrix
     * @param maxMapsPerMachine
     *            The number of maximum map instances on a given machine
     * @param numOfMachines
     *            The number of resources that should be utilized.
     * @throws DatasetException
     *             If there are problems initializing the datasets
     * @throws MapReduceException
     *             If there is a MapReduceExcecution because of problems when
     *             setting up the roles.
     * @throws IOException
     *             If there are IO problems.
     * @throws CommunicationsException
     *             If there are network problems during communications
     * @throws DeploymentException
     *             If there are deployment related problems
     * @throws MarshallingException
     *             If there are marshalling problems.
     * @throws InterruptedException
     *             If there are problems sleeping
     * @throws ServiceException
     *             This is a streaming substrate specific exception
     * @throws NBEventException
     *             If there are problems constructing stream fragments.
     */
    public void generateWorkload(int numOfRows, int numOfColumns,
                                 int maxMapsPerMachine, int numOfMachines)
        throws DatasetException, MapReduceException, CommunicationsException,
        DeploymentException, MarshallingException, InterruptedException,
        ServiceException, NBEventException, IOException {
        this.numberOfMachines = numOfMachines;
        String jobId = createJobIdentifier();

        String report = "";
        if (!matricesInitialized) {
            report =
                "The matrices are NOT being read from files."
                    + "The rows and columns will be generated on the FLY. \n"
                    + "To READ the matrices FROM FILES, please use appropriate"
                    + "commands from the prompt.\n";
        } else {
            report =
                "The matrices WILL BE read from FILES. \n"
                    + "MatrixA is read from file (" + filenameA
                    + "), Matrix B is read from file (" + filenameB + "\n";
        }

        report +=
            ("Number of Machines =" + numberOfMachines + "\n"
                + "Number of maps per machine =" + maxMapsPerMachine + "\n");
        System.out.println(report);

        for (int i = 0; i < numOfColumns;) {
            int columnStart = i;
            int pendingColumns = numOfColumns - i;

            int totalMapsToBeDeployed = maxMapsPerMachine * numOfMachines;

            if (pendingColumns < totalMapsToBeDeployed) {
                totalMapsToBeDeployed = pendingColumns;
            }

            MatrixMap[] maps = new MatrixMap[totalMapsToBeDeployed];

            int j = 0;
            while (totalMapsToBeDeployed != 0) {
                maps[j] = initializeMatrixMap(0, i, numOfRows);
                totalMapsToBeDeployed--;
                j++;
                i++;
            }
            int columnEnd = i;

            /** Deploy the set of maps */
            deployMaps(maps, numOfMachines, jobId);

            /** Make sure that all the maps are up and running first */
            totalMapsToBeDeployed = maxMapsPerMachine * numOfMachines;
            if (pendingColumns < totalMapsToBeDeployed) {
                totalMapsToBeDeployed = pendingColumns;
            }

            while (startCount != totalMapsToBeDeployed) {
                Thread.sleep(50);
            }

            /** Now generate the matrix-B column streams for these map functions */
            generateMatrixBColumnStreams(columnStart, columnEnd, numOfRows);

            Thread.sleep(500);
            generateMatrixARowStreams(numOfRows, numOfColumns,
                                      totalMapsToBeDeployed);

            System.out.println("Processed up until column (" + i
                + ") of the product matrix");
            while (completionCount != totalMapsToBeDeployed) {
                Thread.sleep(50);
            }
            resetTrackers();
        }

        /** Start-off by processing a portion of the columns in B */

        /**
         * For these columns, generate all the rows in A one at a time, so that
         * there is no need to re-transfer the B1-BX partial columns
         */

        /**
         * After it has processed size rows, ... the map instance needs to shut
         * down.
         */
    }


    /**
     * This method takes a set of maps and deploys them on a set of available
     * resources
     * 
     * @param maps
     *            The array of map functions
     * @param numOfResources
     *            The total number of resources
     * @param jobId
     *            The jobId associated with this set of deployments.
     * @throws MarshallingException
     * @throws DeploymentException
     * @throws CommunicationsException
     */
    private void deployMaps(MatrixMap[] maps, int numOfResources, String jobId)
        throws CommunicationsException, DeploymentException,
        MarshallingException {

        deployOperations(maps, numOfResources, jobId);
    }


    /**
     * Generates a set of column streams for the specified range of column
     * streams.
     * 
     * @throws MarshallingException
     * @throws IOException
     * @throws NBEventException
     * @throws ServiceException
     */
    private void generateMatrixBColumnStreams(int start, int end, int numOfRows)
        throws ServiceException, NBEventException, IOException,
        MarshallingException {
        System.out.println("Generating streams for columns (" + start + ")-("
            + end + ")");
        String publishTo = "";

        for (int i = start; i < end; i++) {
            int[] column = getMatrixBColumnStream(i, numOfRows);

            publishTo = columnStream + i;
            publishEvent(publishTo, column);
        }

    }


    private int[] getMatrixBColumnStream(int columnId, int numOfRows)
        throws IOException {
        if (matricesInitialized) {
            return matrixB.readIntMatrixColumn(columnId);
        }

        int[] column = new int[numOfRows];
        // Populate entries for the column
        for (int j = 0; j < numOfRows; j++) {
            column[j] = random.nextInt();
        }
        return column;

    }


    /**
     * Generates a set of column streams for the specified range of row streams.
     * 
     * @param numOfRows
     *            The number of rows that need to be generated
     * @param numOfColumns
     *            The number of columns within the matrix
     * @param numOfDeployedMaps
     *            The number of deployed maps
     * 
     * @throws IOException
     *             If there are IO problems.
     * @throws CommunicationsException
     *             If there are network problems during communications
     * @throws DeploymentException
     *             If there are deployment related problems
     * @throws MarshallingException
     *             If there are marshalling problems.
     * @throws InterruptedException
     *             If there are problems sleeping
     * @throws ServiceException
     *             This is a streaming substrate specific exception
     * @throws NBEventException
     *             If there are problems constructing stream fragments.
     * 
     */
    public void generateMatrixARowStreams(int numOfRows, int numOfColumns,
                                          int numOfDeployedMaps)
        throws ServiceException, NBEventException, IOException,
        MarshallingException, InterruptedException, CommunicationsException {
        String publishTo = "";
        System.out.println("Generating row streams");
        int numOfRowsATime = 1000;

        int generatedRowCounter = 0;
        for (int i = 0; i < numOfRows;) {
            int[] row = getMatrixARowStream(i, numOfColumns);
            if (row.length != numOfColumns) {
                System.out.println(moduleName + "Tried to read row with ("
                    + numOfColumns + ") elements, but returned row has ["
                    + row.length + "] elements!");
            }
            // System.out.print(i + " ");
            /**
             * Make sure that all the Maps have processed the previous row,
             * before you go ahead and send in the next row.
             */

            if (workUnits != 0) {
                String report =
                    "\nWork units = " + workUnits + " will sleep till "
                        + numOfRowsATime + " rows are processed";
                System.out.println(report);
            }

            while (workUnits != 0) {
                Thread.sleep(10);
            }

            // workUnits = numberOfMachines;

            // for (int j = 0; j < numOfRowsATime; j++) {
            publishTo = rowStream + i;
            publishToStream(publishTo, row);
            i++;
            // Thread.sleep(20);

            generatedRowCounter++;
            if (generatedRowCounter == numOfRowsATime) {
                workUnits = numberOfMachines;
                generatedRowCounter = 0;

            }

            // }
        }
    }


    private int[] getMatrixARowStream(int rowId, int numOfColumns)
        throws IOException {
        if (matricesInitialized) {
            return matrixA.readIntMatrixRow(rowId);
        }

        int[] row = new int[numOfColumns];
        // Populate entries for the row in question
        for (int j = 0; j < numOfColumns; j++) {
            row[j] = random.nextInt();
        }
        return row;
    }


    public void generateMatrixStreams(int size, int rowA, int columnB)
        throws ServiceException, NBEventException, IOException,
        MarshallingException, InterruptedException {

        while ((workUnits - completionCount) > 1000) {
            Thread.sleep(100);
        }

        workUnits++;

        String publishTo = "";
        Random random = new Random();

        int[] column = new int[size];
        /** Generate column streams for matrix B */
        for (int i = 0; i < size; i++) {
            column[i] = random.nextInt();
        }
        publishTo = columnStream + columnB;
        publishEvent(publishTo, column);

        int[] row = new int[size];
        /** Generate row stream for matrix A */
        for (int i = 0; i < size; i++) {
            row[i] = random.nextInt();
        }
        publishTo = rowStream + rowA;
        publishEvent(publishTo, row);
    }


    private void publishEvent(String publishingTopic, int[] generatedNumbers)
        throws ServiceException, NBEventException, IOException,
        MarshallingException {

        NBEvent nbEvent =
            producer.generateEvent(TemplateProfileAndSynopsisTypes.STRING,
                                   publishingTopic,
                                   resultPayload.getBytes(generatedNumbers));
        producer.publishEvent(nbEvent);
    }


    private synchronized void publishToStream(String publishStream,
                                              int[] generatedNumbers)
        throws CommunicationsException, ServiceException, MarshallingException {
        NBEvent nbEvent;

        nbEvent =
            producer.generateEvent(
                                   TemplateProfileAndSynopsisTypes.HIERARCHICAL,
                                   publishStream,
                                   resultPayload.getBytes(generatedNumbers));
        producer.publishEvent(nbEvent);

    }


    /**
     * Utility method which allows a consumer to consume a specific stream
     * 
     * @param synopsisType
     *            The synopsis type of the underlying stream
     * @param streamSynopsis
     *            The synopsis for the stream
     * @throws CommunicationsException
     *             When communication problems are encountered.
     */
    private void consumeStream(String streamSynopsis, int synopsisType)
        throws CommunicationsException {
        try {
            System.out.println(moduleName + "Entity ID="
                + consumer.getEntityId());
            Profile profile =
                streamingService.createProfile(streamSynopsis, synopsisType);
            consumer.subscribeTo(profile);

        } catch (ServiceException serEx) {
            serEx.printStackTrace();
            throw new CommunicationsException(serEx.toString());

        }
    }


    public synchronized void onEvent(NBEvent nbEvent) {
        System.out.println("Received result ...");
        String contentSynopsis = (String) nbEvent.getContentSynopsis();
        if (contentSynopsis.startsWith(workUnitStream)) {
            workUnits--;
            if (workUnits < 0) {
                System.out.println("WorkUnits = " + workUnits
                    + " .... problem!");
            }
            return;
        }

        if (contentSynopsis.startsWith(computedColumnStream)) {
            try {
                String columnString =
                    contentSynopsis.substring(computedColumnStream.length());
                int columnId = Integer.parseInt(columnString);
                byte[] payload = nbEvent.getContentPayload();

                ResultsFactory resultsFactory = ResultsFactory.getInstance();
                Results results = resultsFactory.getResults(payload);

                byte[] resultsPayload = results.getResultPayload();

                int[] column = resultPayload.getIntArray(resultsPayload);
                String report =
                    " computed column [" + columnId + "] of length ="
                        + column.length;
                if (matrixC != null) {
                    matrixC.writeIntMatrixColumn(columnId, column);
                    System.out.println(moduleName + "WROTE the" + report);
                } else {
                    System.out.println(moduleName + "Received the" + report);
                }
            } catch (MarshallingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                System.out.println(e);
                e.printStackTrace();
            }
        }

    }


    public static void main(String[] args) {
        try {
            String module = "MatrixDeployer.main()->";
            if (args.length < 2) {
                System.out.println("Usage: java cgl.granules.samples.matrix."
                    + "MatrixDeployer <hostname> <port>");
                System.exit(0);
            }
            String hostname = args[0];
            String portnum = args[1];
            String commType = "niotcp";
            if (args.length == 3) {
                commType = args[2];
            }

            Properties streamingProperties = new Properties();
            streamingProperties.put("hostname", hostname);
            streamingProperties.put("portnum", portnum);

            MatrixDeployer deployer =
                new MatrixDeployer(streamingProperties, commType);

            String helpInfo =
                "\n\nThis is a test program that demonstrates the use of "
                    + "streams in computing matrix products on a set of machines "
                    + "using Granules.The current list of commands include: \n"
                    + "init-matrices <fileA> <fileB> <matrix-dimension>\n"
                    + "submit <#machines> <#map-per-machine> <matrix-dimension>"
                    + ": This runs the benchmark \n"
                    + "status             : List the status of all Jobs \n"
                    + "h                  : List the set of commands \n\n";

            InputStreamReader isr = new InputStreamReader(System.in);
            BufferedReader commandLine = new BufferedReader(isr);

            System.out.println(helpInfo);

            int dimension = 16000;

            StringTokenizer tok;
            while (true) {
                String s = commandLine.readLine();
                if (s == null) {
                    System.out.println(module + "String is null!!!");
                    break;
                }

                if (s.startsWith("init-matrices")) {
                    tok = new StringTokenizer(s);
                    if (tok.countTokens() != 4) {
                        System.out.println("Correct usage is: init-matrices"
                            + " <fileA> <fileB> <matrix-dimension>");
                        continue;
                    }
                    tok.nextToken(); /* ignore the init-matricies token */
                    String fileA = tok.nextToken();
                    String fileB = tok.nextToken();
                    dimension = Integer.parseInt(tok.nextToken());
                    deployer.createBenchmarkMatrices(fileA, dimension,
                                                     dimension, fileB,
                                                     dimension, dimension);
                    continue;
                }

                if (s.startsWith("submit")) {
                    tok = new StringTokenizer(s);
                    System.out.println(module
                        + "Processing the [submit] command");
                    if (tok.countTokens() != 4) {
                        System.out.println("Correct usage is:submit <#machines>"
                            + "  <#map-per-machine> <matrix-dimension>");
                        continue;
                    }
                    tok.nextToken(); /* ignore the matrix-module token */

                    int numOfMachines = Integer.parseInt(tok.nextToken());
                    int maxMapsPerMachine = Integer.parseInt(tok.nextToken());
                    dimension = Integer.parseInt(tok.nextToken());
                    int size = dimension;
                    int numOfRows = size;
                    int numOfColumns = size;

                    deployer.setStartTime();
                    deployer.generateWorkload(numOfRows, numOfColumns,
                                              maxMapsPerMachine, numOfMachines);
                    continue;
                }

                if (s.equals("reset")) {
                    deployer.setStartTime(); /* utility counts */
                }

                if (s.equals("h")) {
                    System.out.println(helpInfo);
                    continue;
                }

                if (s.startsWith("status")) {
                    System.out.println(deployer.getStatus());
                    continue;
                }

                if (s.equals("q")) {
                    System.out.print(module
                        + "Exiting the sample instance deployer");
                    break;
                }

                if (s.equals("p")) {
                    System.out.println(deployer.getStatus());
                }

            }/* end while (true) */

        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}
